
LIBRARY IEEE;             
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE WORK.TYPES.ALL;

ENTITY Idecode IS
    PORT(   read_data_1 : OUT MEMDATA;
            read_data_2 : OUT MEMDATA;
            Instruct    : IN  INSTRUCTION;
            read_data   : IN  MEMDATA;
            ALU_result  : IN  MEMDATA;
            RegWrite    : IN  STD_LOGIC;
            MemtoReg    : IN  STD_LOGIC;
            WrAddr      : IN  REGADDR;
            Sign_extend : OUT MEMDATA;
            clock,reset : IN  STD_LOGIC
    );
END Idecode;


ARCHITECTURE behavior OF Idecode IS
TYPE register_file IS ARRAY ( 0 TO 31 ) OF MEMDATA;

    SIGNAL register_array           : register_file;
    SIGNAL write_register_address   : REGADDR;
    SIGNAL write_data               : MEMDATA;
    SIGNAL read_register_1_address  : REGADDR;
    SIGNAL read_register_2_address  : REGADDR;
    SIGNAL Instruct_immediate_value : STD_LOGIC_VECTOR( 15 DOWNTO 0 );

BEGIN
    read_register_1_address     <= Instruct( 25 DOWNTO 21 );
    read_register_2_address     <= Instruct( 20 DOWNTO 16 );
    Instruct_immediate_value    <= Instruct( 15 DOWNTO 0 );

    -- Leitura do registrador 1
    read_data_1 <= register_array( CONV_INTEGER( read_register_1_address ) );

    -- Leitura do registrador 2         
    read_data_2 <= register_array( CONV_INTEGER( read_register_2_address ) );

    -- Registrar escrita
    write_register_address <= WrAddr;

    -- Mux para memoria 
    write_data <= ALU_result    WHEN ( MemtoReg = '0' )     
                                ELSE read_data;

    Sign_extend (31 DOWNTO 16) <= (OTHERS => Instruct(15));
    Sign_extend (15 DOWNTO 0)  <= Instruct_immediate_value;

PROCESS
    BEGIN
        WAIT UNTIL clock'EVENT AND clock = '1';
        IF reset = '1' THEN
            -- Define o valor inicial dos registradores 
            -- Usa um loop infinito para logica de reset de todos os registradores
            FOR i IN 0 TO 31 LOOP
                register_array(i) <= CONV_STD_LOGIC_VECTOR( i, 32 );
            END LOOP;
            -- Reescrita dos dados nos registradores, exceto no
            -- registrador 0
        ELSIF RegWrite = '1' AND write_register_address /= 0 THEN
              register_array( CONV_INTEGER( write_register_address ) ) <= write_data;
        END IF;
    END PROCESS;
END behavior;


